/**
 * @file pipeline.cpp
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2024-02-01
 *
 * @copyright Copyright (c) 2024
 *
 */
#include "pipeline.h"

#include "CGraph.h"

using namespace CGraph;
/**
 * PipeFrame 是GParam的具体实现类
 * 本例中使用 struct 类型，是为了使得 参数权限 默认为是public类型
 * 如果使用 class 类型，请注意 参数权限 默认是private类型信息
 */
struct PipeFrame : public CGraph::GParam
{
    PipeFrame()
    {
        frame = std::make_shared<ImageFrame>();
    }
    /**
     * reset方法，在pipeline执行一次结束的时候被调用。
     * 如果是pipeline多次执行，并且依赖之前pipeline运行的结果（如，通过iCount值，记录pipeline执行了多少次）
     * reset中，不要实现重置参数逻辑即可
     */
    CVoid reset(const CStatus &curStatus) override {}

    ImageFramePtr frame;
};

class ReadWriteParamNode : public CGraph::GNode
{
   public:
    CStatus init() override
    {
        CStatus status;
        // auto *frame = CGRAPH_GET_EPARAM(PipeFrame, "frame");
        auto *frame = CGRAPH_GET_GPARAM(PipeFrame, "frame");

        if (nullptr == frame)
        {
            status = CGRAPH_CREATE_GPARAM(PipeFrame, "frame");
        }
        return status;
    }

    CStatus run() override
    {
        /**
         * 为了提高执行效率，
         * 在【创建参数】的时候，【提供】锁保护机制
         * 在【获取参数】的时候，【不提供】锁保护的机制
         * 故无法通过在run()过程中，并发的通过 createGParam 和 getGParam
         * 创建和获取参数 如果需要做此操作，请自行外部加锁
         */
        uint64_t curr_val = 0;
        uint64_t run_val  = 0;

        auto frame = CGRAPH_GET_GPARAM_WITH_NO_EMPTY(PipeFrame, "frame");
        {
            CGRAPH_PARAM_WRITE_CODE_BLOCK(frame)
            /**
             * 建议将需要的内容获取出来，然后在 CODE_BLOCK
             * 外进行与param无关的参数加工（本例中为：打印信息）。
             * 这样做的好处，是可以尽可能减少 CODE_BLOCK 的范围
             */
            curr_val                       = frame->frame->on_receive_timestamp++;
            frame->frame->on_run_timestamp = frame->frame->on_receive_timestamp++;
            run_val                        = frame->frame->on_run_timestamp;
        }

        /* 执行时，仅依赖val值，跟当前param1->iValue值无关，可以放到 CODE_BLOCK 外部
         */
        CGraph::CGRAPH_ECHO("[%s], on_receive_timestamp is : [%d] "
                            "on_receive_timestamp is : [%d] ... ",
                            this->getName().c_str(), curr_val, run_val);

        return CStatus();
    }
};

void test_pipeline()
{
    GPipelinePtr pipeline = GPipelineFactory::create();
    CStatus status;
    GElementPtr a, b, c, d, e, f = nullptr;

    status += pipeline->registerGElement<ReadWriteParamNode>(&a, {}, "readNodeA");

    status += pipeline->registerGElement<ReadWriteParamNode>(&b, {a}, "readNodeB");
    status += pipeline->registerGElement<ReadWriteParamNode>(&c, {a}, "writeNodeC");
    status += pipeline->registerGElement<ReadWriteParamNode>(&d, {a}, "writeNodeD", 2);
    status += pipeline->registerGElement<ReadWriteParamNode>(&e, {a}, "readNodeE");
    status += pipeline->registerGElement<ReadWriteParamNode>(&f, {b, c, d, e}, "writeNodeF");
    if (!status.isOK())
    {
        return;
    }

    status += pipeline->init();

    for (int i = 0; i < 3; i++)
    {
        status += pipeline->run();
        std::cout << "[CGraph] tutorial_param, loop : " << i + 1 << ", and run status = " << status.getCode() << std::endl;
    }

    /**
    auto param = pipeline->getGParam<PipeFrame>("param1");    //
    可以获取pipeline内部的参数内容。但是需要考虑param的setup()和reset()的时机
    std::cout << "[CGraph] get param from pipeline, iCount = " << param->iCount <<
    std::endl;
    */

    status += pipeline->destroy();
    GPipelineFactory::remove(pipeline);
}
